package net.sf.odinms.net.channel.handler;

import java.util.List;
import net.sf.odinms.client.MapleCharacter;
import net.sf.odinms.client.MapleClient;
import net.sf.odinms.client.anticheat.CheatingOffense;
import net.sf.odinms.net.MaplePacket;
import net.sf.odinms.server.maps.FakeCharacter;
import net.sf.odinms.server.movement.AbsoluteLifeMovement;
import net.sf.odinms.server.TimerManager;
import net.sf.odinms.server.movement.LifeMovementFragment;
import net.sf.odinms.tools.MaplePacketCreator;
import net.sf.odinms.tools.data.input.SeekableLittleEndianAccessor;

public class MovePlayerHandler extends AbstractMovementPacketHandler {

    //private static Logger log = LoggerFactory.getLogger(MovePlayerHandler.class);

    @Override
    public void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
        c.getPlayer().resetAfkTime();
        slea.readByte();
        slea.readInt();
        // log.trace("Movement command received: unk1 {} unk2 {}", new Object[] { unk1, unk2 });
        final List<LifeMovementFragment> res = parseMovement(slea);
        if (res != null) {
            if (slea.available() != 18) {
                return;
            }
            MapleCharacter player = c.getPlayer();
            MaplePacket packet = MaplePacketCreator.movePlayer(player.getId(), res);
            if (!player.isHidden()) {
                c.getPlayer().getMap().broadcastMessage(player, packet, false);
            } else {
                c.getPlayer().getMap().broadcastGMMessage(player, packet, false);
            }
            // c.getSession().write(MaplePacketCreator.movePlayer(30000, res));
            if (CheatingOffense.FAST_MOVE.isEnabled() || CheatingOffense.HIGH_JUMP.isEnabled()) {
                checkMovementSpeed(c.getPlayer(), res);
            }
            updatePosition(res, c.getPlayer(), 0);
            c.getPlayer().getMap().movePlayer(c.getPlayer(), c.getPlayer().getPosition());

            if (c.getPlayer().hasFakeChar()) {
                int i = 1;
                for (final FakeCharacter ch : c.getPlayer().getFakeChars()) {
                    if (ch.follow() && ch.getFakeChar().getMap() == player.getMap()) {
                        TimerManager.getInstance().schedule(new Runnable() {

                            @Override
                            public void run() {
                                ch.getFakeChar().getMap().broadcastMessage(ch.getFakeChar(), MaplePacketCreator.movePlayer(ch.getFakeChar().getId(), res), false);
                                updatePosition(res, ch.getFakeChar(), 0);
                                ch.getFakeChar().getMap().movePlayer(ch.getFakeChar(), ch.getFakeChar().getPosition());
                            }
                        }, i * 300);
                        i++;
                    }
                }
            }
        }
    }

    private static void checkMovementSpeed(MapleCharacter chr, List<LifeMovementFragment> moves) {
        // boolean wasALM = true;
        // Point oldPosition = new Point (c.getPlayer().getPosition());
        double playerSpeedMod = chr.getSpeedMod() + 0.005;
        // double playerJumpMod = c.getPlayer().getJumpMod() + 0.005;
        boolean encounteredUnk0 = false;
        for (LifeMovementFragment lmf : moves) {
            if (lmf.getClass() == AbsoluteLifeMovement.class) {
                final AbsoluteLifeMovement alm = (AbsoluteLifeMovement) lmf;
                double speedMod = Math.abs(alm.getPixelsPerSecond().x) / 125.0;
                // int distancePerSec = Math.abs(alm.getPixelsPerSecond().x);
                // double jumpMod = Math.abs(alm.getPixelsPerSecond().y) / 525.0;
                // double normalSpeed = distancePerSec / playerSpeedMod;
                // System.out.println(speedMod + "(" + playerSpeedMod + ") " + alm.getUnk());
                if (speedMod > playerSpeedMod) {
                    if (alm.getUnk() == 0) { // to prevent FJ messing up
                        encounteredUnk0 = true;
                    }
                    if (!encounteredUnk0) {
                        if (speedMod > playerSpeedMod) {
                            chr.getCheatTracker().registerOffense(CheatingOffense.FAST_MOVE);
                        }
                    }
                }
            // if (wasALM && (oldPosition.y == newPosition.y)) {
            // int distance = Math.abs(oldPosition.x - newPosition.x);
            // if (alm.getDuration() > 60) { // short durations are strange and show too fast movement
            // double distancePerSec = (distance / (double) ((LifeMovement) move).getDuration()) * 1000.0;
            // double speedMod = distancePerSec / 125.0;
            // double normalSpeed = distancePerSec / playerSpeedMod;
            // System.out.println(speedMod + " " + normalSpeed + " " + distancePerSec + " " + distance + " "
            // + alm.getWobble());
            // }
            // }
            // oldPosition = newPosition;
            // wasALM = true;
            // } else {
            // wasALM = false;
            }
        }
    }
}